package com.game.doudizhu.service;

import com.game.doudizhu.core.AIRealGameTrainer;
import com.game.doudizhu.core.AIStrategy;
import com.game.doudizhu.core.DoudizhuGameLogic;
import com.game.doudizhu.model.*;
import com.game.doudizhu.common.constants.GameConstants;
import com.game.doudizhu.common.exception.GameException;
import lombok.Data;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.messaging.simp.SimpMessagingTemplate;
import org.springframework.scheduling.TaskScheduler;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.core.JsonProcessingException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.time.Instant;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executor;
import java.util.stream.Collectors;

@Service
public class GameService {

    private static final Logger logger = LoggerFactory.getLogger(GameService.class);

    @Autowired
    private GameRoomService gameRoomService;
    
    @Autowired
    private PlayerService playerService;
    
    @Autowired
    private DoudizhuGameLogic gameLogic;
    
    @Autowired
    private CardService cardService;
    
    @Autowired
    private SimpMessagingTemplate messagingTemplate;
    
    @Autowired
    private TaskScheduler taskScheduler;

    @Autowired
    private ObjectMapper objectMapper;

    @Autowired
    private StatisticsService statisticsService;

    private final Map<Long, GameState> gameStates = new ConcurrentHashMap<>();

    @Autowired
    private Executor aiTaskExecutor;

    @Autowired
    private GameMessageService gameMessageService;

    // 存储游戏记录的Map
    private final Map<Long, GameRecord> gameRecords = new ConcurrentHashMap<>();

    // === 业务方法 ===
    @Transactional
    public GameRoom handlePlayerJoin(Long roomId, Player player) {
        GameRoom room = gameRoomService.getRoom(roomId);
        player = playerService.getPlayer(player.getId());
        if (gameRoomService.isPlayerReconnecting(room, player) ) {
            gameRoomService.handlePlayerReconnect(room, player);
            restorePlayerState(player, getGameState(roomId));
            // 记录加入房间的动作
            GameState gameState = getGameState(roomId);
            if (gameState != null) {
                GameAction joinAction = GameAction.createJoinAction(
                        player.getId(),
                        player.getUsername()
                );
                gameState.addGameAction(joinAction);
                notifyGameStateUpdate(roomId, gameState);
            }
        } else {
            gameRoomService.addNewPlayer(room, player);
        }
        
        return room;
    }

    @Transactional
    public GameRoom handlePlayerReady(Long roomId, Player player) {
        GameRoom room = gameRoomService.getRoom(roomId);
        player = playerService.getPlayer(player.getId());
        gameRoomService.togglePlayerReady(room, player);
        
        if (gameRoomService.canStartGame(room)) {
            startNewGame(room);
        }
        
        return room;
    }

    @Transactional
    public GameState handleBid(Long roomId, BidMessage bidMessage) {
        GameState gameState = getGameStateOrThrow(roomId);
        GameRoom room = gameRoomService.getRoom(roomId);
        // 处理叫分
        gameLogic.handleBidding(gameState, bidMessage);

        // 记录叫分动作, 通知游戏状态
        GameAction bidAction = GameAction.createBidAction(
                bidMessage.getPlayerId(),
                playerService.getPlayer(bidMessage.getPlayerId()).getUsername(),
                bidMessage.getBidPoints()
        );
        gameState.addGameAction(bidAction);
        notifyGameStateUpdate(roomId, gameState);
        recordPlayerAction(gameState, bidMessage.getPlayerId(), new ArrayList<>(), false);
        
        // 如果叫分阶段结束
        if (!gameState.isBidding()) {
            if (gameState.isNeedRestart()) {
                startNewGame(room);
                return gameStates.get(roomId);
            } else {
                startPlaying(roomId, gameState);
            }
            return gameState;
        }
        
        // 如果叫分阶段还在继续，检查下一个玩家是否是AI
        Long nextBidder = gameState.getCurrentBidder();
        if (nextBidder != null) {
            Player nextPlayer = playerService.getPlayer(nextBidder);
            if (nextPlayer.isAI()) {
                handleAITurn(gameState, nextBidder);
            }
        }
        
        return gameState;
    }

    @Transactional
    public GameState handlePlayCards(Long roomId, PlayCardMessage playCardMessage) {
        GameState gameState = getGameStateOrThrow(roomId);
        validateGameState(gameState);
        
        // 处理出牌
        List<Card> cardsToPlay = gameLogic.getCardsToPlay(gameState, playCardMessage);
        gameLogic.handlePlayCards(gameState, playCardMessage, cardsToPlay);
        
        // 记录出牌动作,通知游戏状态
        GameAction playAction = GameAction.createPlayAction(
            playCardMessage.getPlayerId(),
            playerService.getPlayer(playCardMessage.getPlayerId()).getUsername(),
            cardsToPlay
        );
        gameState.addGameAction(playAction);
        notifyGameStateUpdate(roomId, gameState);
        recordPlayerAction(gameState, playCardMessage.getPlayerId(), cardsToPlay, true);
        
        // 如果游戏还没结束，检查下一个玩家是否是AI
        if (!gameLogic.isGameOver(gameState)) {
            Long nextPlayerId = gameState.getCurrentPlayerId();
            Player nextPlayer = playerService.getPlayer(nextPlayerId);
            if (nextPlayer.isAI()) {
                handleAITurn(gameState, nextPlayerId);
            }
        } else {
            handleGameOver(roomId, gameState);
        }
        
        return gameState;
    }

    @Transactional
    public GameState handlePlayerPass(Long roomId, Long playerId) {
        GameState gameState = getGameStateOrThrow(roomId);
        validateGameState(gameState);

        Player player = playerService.getPlayer(playerId);

        // 处理过牌逻辑
        gameLogic.handlePass(gameState, player);

        // 记录过牌动作,通知游戏状态
        GameAction passAction = GameAction.createPassAction(
                playerId,
                player.getUsername()
        );
        gameState.addGameAction(passAction);
        notifyGameStateUpdate(roomId, gameState);
        recordPlayerAction(gameState, playerId, new ArrayList<>(), true);

        // 检查下一个玩家是否是AI
        Long nextPlayerId = gameState.getCurrentPlayerId();
        Player nextPlayer = playerService.getPlayer(nextPlayerId);
        if (nextPlayer.isAI()) {
            handleAITurn(gameState, nextPlayerId);
        }

        return gameState;
    }

    public void handlePlayerDisconnect(Long playerId, Long roomId) {
        handlePlayerLeave(roomId, playerId, true);
    }

    @Transactional
    public GameRoom handlePlayerLeave(Long roomId, Long playerId, boolean isDisconnect) {
        GameRoom room = gameRoomService.getRoom(roomId);
        GameState gameState = gameStates.get(roomId);

        if (gameState != null) {
            Player player = playerService.getPlayer(playerId);
            if (player != null) {
                // 记录离开动作
                GameAction leaveAction = GameAction.createLeaveAction(
                    playerId,
                    player.getUsername()
                );
                gameState.addGameAction(leaveAction);
                notifyGameStateUpdate(roomId, gameState);
            }
        }

        if (isDisconnect) {
            // 如果是断开连接，录断开状态，不立即移除玩家
            gameRoomService.handlePlayerDisconnect(roomId, playerId);
            schedulePlayerRemoval(playerId, roomId);
            return room;
        } else {
            // 如果是主动离开，直接处理离开逻辑
            if (gameState != null) {
                Player player = playerService.getPlayer(playerId);
                if (player != null) {
                    recordLeaveAction(gameState, player);
                }
            }
            
            room = gameRoomService.handlePlayerLeave(roomId, playerId);
            if (room == null || room.getPlayers().size() < 2) {
                gameStates.remove(roomId);
            }
            
            return room;
        }
    }

    @Transactional
    public void restorePlayerState(Player player, GameState gameState) {
        List<Card> playerCards = gameState.getPlayerCards().get(player.getId());
        if (playerCards != null) {
            player.setCards(new ArrayList<>(playerCards));
        }

        if (player.getId().equals(gameState.getLandlordId())) {
            player.setRole(GameConstants.Role.LANDLORD);
        } else {
            player.setRole(GameConstants.Role.FARMER);
        }

        if (gameState.getRoom().getStatus().equals(GameConstants.Status.WAITING)) {
            player.setReady(false);
        }

        gameState.getRoom().getPlayers().stream()
            .filter(p -> p.getId().equals(player.getId()))
            .findFirst()
            .ifPresent(p -> {
                p.setCards(player.getCards());
                p.setRole(player.getRole());
                p.setReady(player.isReady());
            });
    }

    // === 辅助方法 ===
    private GameState getGameStateOrThrow(Long roomId) {
        return Optional.ofNullable(gameStates.get(roomId))
            .orElseThrow(() -> new GameException("游戏未开始"));
    }

    private void startNewGame(GameRoom room) {
        GameState gameState = gameLogic.initializeGame(room);
        gameStates.put(room.getId(), gameState);


        gameRoomService.updateRoomStatus(room.getId(), GameConstants.Status.PLAYING);
        
        List<Card> cards = cardService.initializeAndDealCards(room.getId());
        cardService.distributeCards(cards, gameState);
        
        // 设置叫分阶段标志
        gameState.setBidding(true);
        gameState.setBiddingPhase(true);
        
        notifyGameStart(room.getId(), gameState);

        // 检查第一个叫分的玩家是否是AI
        Long firstBidder = gameState.getCurrentBidder();
        if (firstBidder != null) {
            Player firstPlayer = playerService.getPlayer(firstBidder);
            if (firstPlayer.isAI()) {
                handleAITurn(gameState, firstBidder);
            }
        }
    }

    private void startPlaying(Long roomId, GameState gameState) {
        gameLogic.startPlaying(gameState);
        
        // 游戏开始后，如果第一个玩家是AI，则触发AI操作
        Long firstPlayerId = gameState.getCurrentPlayerId();
        Player firstPlayer = playerService.getPlayer(firstPlayerId);
        if (firstPlayer.isAI()) {
            handleAITurn(gameState, firstPlayerId);
        }
    }

    @Transactional
    public void handleGameOver(Long roomId, GameState gameState) {
        // 计算最终分数
        gameLogic.calculateFinalScores(gameState);
        
        // 更新房间状态
        gameRoomService.updateRoomStatus(roomId, GameConstants.Status.FINISHED);
        
        // 更新玩家统计数据
        Map<Long, Integer> playerScores = gameState.getPlayerScores();
        Long winnerId = gameState.getWinner();
        
        playerScores.forEach((playerId, score) -> {
            String role = playerId.equals(gameState.getLandlordId()) ? GameConstants.Role.LANDLORD : GameConstants.Role.FARMER;
            statisticsService.updateGameStatistics(playerId, playerId.equals(winnerId), score, role);
        });
        
        // 创建游戏结束的动作,通知所有玩家游戏结束
        GameAction gameOverAction = GameAction.createGameOverAction(
            gameState.getWinner(),
            gameState.getPlayerScores()
        );
        gameState.addGameAction(gameOverAction);
        notifyGameStateUpdate(roomId, gameState);
        
        // 设置延迟后开始新一局
        taskScheduler.schedule(
            () -> {
                try {
                    startNewGameWithTransaction(gameState.getRoom());
                } catch (Exception e) {
                    e.printStackTrace();
                    sendErrorMessage(
                        roomId,
                        "NEED_REJOIN",
                        "开始新游戏失败，请重新入房间",
                        "NEW_GAME_FAILED"
                    );
                }
            },
            Instant.now().plusSeconds(5)
        );

        // 清理游戏记录
        cleanupGameRecord(roomId);
    }

    @Transactional
    public void startNewGameWithTransaction(GameRoom room) {
        startNewGame(room);
    }

    private void notifyGameStart(Long roomId, GameState gameState) {
        messagingTemplate.convertAndSend("/topic/game/" + roomId, gameState);
        gameMessageService.sendGameStateUpdate(roomId, gameState);
    }

    private void notifyGameStateUpdate(Long roomId, GameState gameState) {
        gameMessageService.sendGameStateUpdate(roomId, gameState);
    }

    private void validateGameState(GameState gameState) {
        if (!gameState.isPlaying()) {
            throw new GameException("游戏尚未开始");
        }
        if (gameState.isGameOver()) {
            throw new GameException("游戏已经结束");
        }
    }

    private void recordJoinAction(Long roomId, Player player) {
        GameAction joinAction = GameAction.createJoinAction(
            player.getId(), 
            player.getUsername()
        );
        gameStates.get(roomId).addGameAction(joinAction);
    }

    private void recordLeaveAction(GameState gameState, Player player) {
        GameAction leaveAction = GameAction.createLeaveAction(
            player.getId(),
            player.getUsername()
        );
        gameState.addGameAction(leaveAction);
    }

    private void schedulePlayerRemoval(Long playerId, Long roomId) {
        taskScheduler.schedule(
            () -> {
                GameRoom room = gameRoomService.getRoom(roomId);
                if (room != null && gameRoomService.shouldRemovePlayer(room, playerId.toString())) {
                    // 到达超时时间后，如果玩家仍未重连，则执行实际的离开逻辑
                    handlePlayerLeave(roomId, playerId, false);
                }
            },
            Instant.now().plusMillis(GameConstants.Room.RECONNECT_TIMEOUT)
        );
    }

    public GameState getGameState(Long roomId) {
        return getGameStateOrThrow(roomId);
    }

    @Scheduled(fixedRate = 300000) // 每5分钟执行一次
    @Transactional
    public void cleanupInactiveGames() {
        gameStates.forEach((roomId, gameState) -> {
            if (gameState.isGameOver() || 
                gameState.getRoom().getPlayers().size() < GameConstants.Room.MIN_PLAYERS) {
                gameStates.remove(roomId);
            }
        });
    }

    public GameState getRoomStatus(Long roomId) {
        return Optional.ofNullable(gameStates.get(roomId))
                .orElseThrow(() -> new GameException("游戏未开始"));
    }

    private void sendErrorMessage(Long roomId, String type, String message, String code) {
        gameMessageService.sendErrorMessage(roomId, type, message, code);
    }

    // 处理AI玩家的操作
    public void handleAITurn(GameState gameState, Long aiPlayerId) {
        try {
            Player player = playerService.getPlayer(aiPlayerId);
            if (!player.isAI()) {
                return;
            }

            // 检查是否轮到该AI操作
            if (gameState.isBidding() && !aiPlayerId.equals(gameState.getCurrentBidder())) {
                logger.debug("不是AI叫分回合: {}", aiPlayerId);
                return;
            }
            if (!gameState.isBidding() && !aiPlayerId.equals(gameState.getCurrentPlayerId())) {
                logger.debug("不是AI出牌回合: {}", aiPlayerId);
                return;
            }

            logger.debug("AI turn id: {}, name: {} ", player.getId(), player.getUsername());

            // 使用线程池执行AI操作
            aiTaskExecutor.execute(() -> {
                try {
                    // 添加延迟，模拟AI思考时间
                    Thread.sleep(1000);

                    // 再次检查是否轮到该AI操作
                    if (gameState.isBidding() && !aiPlayerId.equals(gameState.getCurrentBidder())) {
                        logger.debug("AI叫分回合已过: {}", aiPlayerId);
                        return;
                    }
                    if (!gameState.isBidding() && !aiPlayerId.equals(gameState.getCurrentPlayerId())) {
                        logger.debug("AI出牌回合已过: {}", aiPlayerId);
                        return;
                    }

                    // 获取AI玩家的手牌
                    List<Card> handCards = gameState.getPlayerCards().get(aiPlayerId);
                    
                    if (gameState.isBidding()) {
                        // AI叫分
                        handleAIBid(gameState, aiPlayerId, handCards);
                    } else {
                        // AI出牌
                        handleAIPlay(gameState, aiPlayerId, handCards);
                    }

                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                } catch (Exception e) {
                    // 记录错误并继续游戏
                    logger.error("AI操作出错: {}", e.getMessage());
                    // 确保游戏不会卡住，移交给下一个玩家
                    if (!gameState.isBidding()) {
                        gameLogic.moveToNextPlayer(gameState);
                        notifyGameStateUpdate(gameState.getRoomId(), gameState);
                    }
                }
            });
        } catch (Exception e) {
            logger.error("提交AI任务失败: {}", e.getMessage());
        }
    }

    private void handleAIBid(GameState gameState, Long aiPlayerId, List<Card> handCards) {
        int bidPoints = AIStrategy.decideBid(handCards, gameState.getMaxBid());
        logger.debug("AI do bid id: {}, points: {} ", aiPlayerId, bidPoints);
        
        BidMessage bidMessage = new BidMessage();
        bidMessage.setPlayerId(aiPlayerId);
        bidMessage.setBidPoints(bidPoints);
        
        // 调用 handleBid
        handleBid(gameState.getRoomId(), bidMessage);
    }

    private void handleAIPlay(GameState gameState, Long aiPlayerId, List<Card> handCards) {
        boolean isLandlord = aiPlayerId.equals(gameState.getLandlordId());
        List<Card> cardsToPlay = AIStrategy.decideCards(handCards, gameState.getLastPlayedCards(), isLandlord, gameState);
        logger.debug("AI do play id: {}, cards: {} ", aiPlayerId, cardsToPlay);
        
        if (cardsToPlay.isEmpty()) {
            // 调用 handlePlayerPass
            handlePlayerPass(gameState.getRoomId(), aiPlayerId);
        } else {
            // AI出牌
            PlayCardMessage playCardMessage = new PlayCardMessage();
            playCardMessage.setPlayerId(aiPlayerId);
            playCardMessage.setCardIds(cardsToPlay.stream()
                    .map(Card::getId)
                    .collect(Collectors.toList()));
            // 调用 handlePlayCards
            handlePlayCards(gameState.getRoomId(), playCardMessage);
        }
    }

    /**
     * 记录玩家行动
     */
    public void recordPlayerAction(GameState gameState, Long playerId, 
            List<Card> playedCards, boolean isPlaying) {
        GameRecord gameRecord = getOrCreateGameRecord(gameState.getRoomId());
        
        PlayerAction action = new PlayerAction();
        action.setPlayerId(playerId);
        action.setLandlord(playerId.equals(gameState.getLandlordId()));
        action.setHandCards(new ArrayList<>(gameState.getPlayerCards().get(playerId)));
        action.setPlayedCards(playedCards);
        action.setLastPlayedCards(gameState.getLastPlayedCards());
        action.setBidValue(gameState.getPlayerBids().getOrDefault(playerId, -1));
        action.setHandStrength(AIStrategy.calculateHandStrength(action.getHandCards()));
        action.setRemainingCards(action.getHandCards().size());
        
        gameRecord.getActions().add(action);
        
        // 如果游戏结束，更新获胜信息并训练AI
        if (!isPlaying) {
            gameRecord.setWinnerId(playerId);
            gameRecord.setLandlordWin(playerId.equals(gameState.getLandlordId()));
            
            // 更新所有行动的获胜状态
            for (PlayerAction recordedAction : gameRecord.getActions()) {
                recordedAction.setWinner(recordedAction.getPlayerId().equals(playerId));
            }
            
            // 训练AI
            AIRealGameTrainer.recordGamePlay(gameRecord);
        }
    }

    /**
     * 获取或创建游戏记录
     * @param roomId 房间ID
     * @return 游戏记录
     */
    private GameRecord getOrCreateGameRecord(Long roomId) {
        return gameRecords.computeIfAbsent(roomId, k -> {
            GameRecord record = new GameRecord();
            record.setRoomId(roomId);
            record.setGameId(generateGameId());
            record.setActions(new ArrayList<>());
            
            // 从游戏状态中获取地主ID
            GameState gameState = getGameState(roomId);
            if (gameState != null) {
                record.setLandlordId(gameState.getLandlordId());
            }
            
            return record;
        });
    }

    /**
     * 生成游戏ID
     * @return 游戏ID
     */
    private Long generateGameId() {
        return System.currentTimeMillis();
    }

    /**
     * 清理已完成的游戏记录
     * 建议在游戏结束时调用
     * @param roomId 房间ID
     */
    private void cleanupGameRecord(Long roomId) {
        gameRecords.remove(roomId);
    }
}